# Module version 0.2.1
# Author: Bartek Bielawski (@bielawb on twitter)
# Purpose: Add functionality to PowerShell ISE
# Description: Adds Add-ons menu 'ISEFun' with all functions included.
#    User can add any action there using Add-MyMenuItem function
#    One of functions (Copy item from history) was build using WPK - won't work if the latter is not loaded.
#    There is also pretty large code for Windows Forms form (change token colors using ColorDialog)
#    Edit-Function will allow you modify any function in ISE editor
#    Expand-Alias will expand aliases in current file
#    Edit-HelpExample will create new file $with all examples from a given command
#    Show-Top will generate table of processes sorted by a given Property in separate ISE Tab, with new/ terminated processes marked
#    Update-SnippetMenu and New-Snippet are designed to work with custom code snippets.
#    Have ISE - Fun! ;)
# Changes:
# Version 0.2.2
# Added function to export/ import token colors settings (.csv used for that)
# Groupped all token functions in one sub-menu.
# Version 0.2.1
# * Added only one new function: Invoke-Script
# * Some typos fixed
# Version 0.2
# * Added function Edit-HelpExample
# * Added function Show-Top
# * Added custom snippets support (add/ use)
# Version 0.1
# * First public version
# * Cleaned code, added help
# * Contains functions: Edit-Function, Add-MenuItem, Set-TokenColor, Expand-Alias, Invoke-CurrentLine, Copy-HistoryItem
# * Simple menu with all functions included, together with helper function (Add-MenuItem) that should simplify adding new items if needed.
#############################################################################################################################################
# ROADMAP:
# * Add support for new files (ps1, psm1, psd1, format.ps1xml, type.ps1xml) with some templates => NewTemplates.psm1
# * Add support for 'Paste Special' (herestring expandable, herestring not expandable, block comment, scriptblock) => PasteSpecial.psm1
# * Simplify building ps1xml by adding support to add new elements (XmlDocument + InnerXML maybe?) => ps1xmlTools.psm1
# * Once shipped - make it possible to easily edit/ import edited file using PowerShell_SE => PowerShell_SE.psm1
    



if (-not ($MyISEMenu = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus | Where-Object { $_.DisplayName -eq 'ISEFun'} ) ) {
    $MyISEMenu = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('ISEFun',$null,$null)
}

# Helper function to add menu items, exported cause it can be used also for other stuff. :>
function Add-MyMenuItem {

<#
    .Synopsis
        Adds items to ISEFun Add-Ons sub-menu
    .Description
        Function can be used to add menu items to ISEFun menu. All you need is command, name and hotkey - we will take care of the rest for you. ;)
    .Example
        Add-MyMenuItem 'Write-Host fooo' 'Fooo!' 'CTRL+9'
        
        Description
        -----------
        This command will add item 'Fooo!' to ISEFun menu. This item will write 'fooo' to the host and can be launched using shortcut CTRL + 9
        
#>

    PARAM (
        # Script that will be launched when menu item will be selected
        [Parameter(Mandatory = $true, HelpMessage = 'Command that you want to add to menu')]
        [string]$Command,
        # Title for the command in the menu
        [string]$DisplayName,
        # Hot key to use given item
        [string]$HotKey = $null,
        # If specified - will create submenu to hold given command
        [string]$SubMenu = $null
    )
    if (!$DisplayName) { 
        $DisplayName = $Command -replace '-',' '
    }
    if (!$SubMenu) {
        $Menu = $Script:MyISEMenu
    } elseif ($Menu = $MyISEMenu.Submenus | Where-Object { $_.DisplayName -eq $SubMenu }) {
        if (!($Menu.submenus)) {
            $Menu = $Script:MyISEMenu
        }
    } else {
        $Menu = $MyISEMenu.Submenus.Add($SubMenu,$null,$null)
    }
    if ( -not ($Menu.Submenus | Where-Object { $_.DisplayName -eq $DisplayName} ) ) {
        try {
            [void]$Menu.Submenus.Add($DisplayName,[scriptblock]::Create($Command),$HotKey)
        } catch {
            # Probably hotkey already used, adding item without it
            [void]$Menu.Submenus.Add($DisplayName,[scriptblock]::Create($Command),$null)
        }
    }
}

Add-MyMenuItem Add-MyMenuItem 'Add items'

function Export-TokenColor {

<#
    .Synopsis
        Exporsts colors to csv file from the current session.
    .Description
        Very simple function to save token color settings to a file. If you do not specify path it will use file dialog to get one from you.
        If you close/ cancel window it will ask you to confirm that that's what you intendendent to do.
    .Example
        Export-TokenColor -Path c:\temp\test.csv
        This command will write settings from c:\temp\test.csv and apply to the current token colors settings. If file already exists, it will prompt for confirmation.
#>

    [CmdletBinding()]
    param (
        # Path to file (csv) where configuration will be stored.
        [Parameter()]
        [Alias('Name','Config')]
        [string]$Path
        )
    if (!$Path) {
        # Need some dialog for path to file
        $Save = New-Object Windows.Forms.SaveFileDialog -Property @{
            Filter = 'Comma Seperated Value file (*.csv)|*.csv'
            Title = 'Where should I store current Token Colors configuration?'
            InitialDirectory = $(Split-Path $Profile)
        }
        $Save.CustomPlaces.Add($(Split-Path $Profile))
        do {
            $result = $Save.ShowDialog()
            if ($result -eq 'Cancel') {
                $Answer = [Windows.Forms.MessageBox]::Show('Do you want to cancel?','Confirm','YesNo','Question')
                if ($Answer = 'Yes') { return }
            }
        } until ($Save.FileName -and ($result -eq 'OK'))
        $Path = $Save.FileName
    } else {
        # If it exists: ask for confirmation on overwrite
        if (Test-Path $Path) {
            $Answer = [windows.forms.messageBox]::Show('Do you want to overwrite existing file?','Confirmation','OKCancel','Question')
            if ($Answer -eq 'Cancel') { return }
        }
    }
    $psISE.Options.TokenColors | Export-Csv -NoTypeInformation $Path
}

Add-MyMenuItem Export-TokenColor 'Export Token Colors to CSV' $null 'Token colors'

function Import-TokenColor {

<#
    .Synopsis
        Imports colors from csv file to the current session.
    .Description
        Very simple function to load token color settings from file. If you do not specify path it will use file dialog to get one from you.
        If you close/ cancel window it will ask you to confirm that that's what you intendendent to do.
    .Example
        Import-TokenColor -Path c:\temp\test.csv
        This command will read settings from c:\temp\test.csv (if exists) and apply to the current token colors settings.
#>

    [CmdletBinding()]
    param (
        # Path to file (csv) where configuration is stored.
        [Parameter()]
        [Alias('Name','Config')]
        [string]$Path
        )
    if (!$Path) {
        # Need some dialog for path to file
        $Save = New-Object Windows.Forms.OpenFileDialog -Property @{
            Filter = 'Comma Seperated Value file (*.csv)|*.csv'
            Title = 'Where can I find new Token Colors configuration?'
            InitialDirectory = $(Split-Path $Profile)
        }
        $Save.CustomPlaces.Add($(Split-Path $Profile))
        do {
            $result = $Save.ShowDialog()
            if ($result -eq 'Cancel') {
                $Answer = [Windows.Forms.MessageBox]::Show('Do you want to cancel?','Confirm','YesNo','Question')
                if ($Answer = 'Yes') { return }
            }
        } until ($Save.FileName -and ($result -eq 'OK'))
        $Path = $Save.FileName
    }
    if (Test-Path $Path) {
        foreach ($record in Import-Csv $Path) { 
            $psISE.Options.TokenColors[$record.Key] = $record.Value
        }
    } else {
        throw 'File does not exist'
    }
}

Add-MyMenuItem Import-TokenColor 'Import Token Colors from CSV' $null 'Token colors'

function Invoke-Script {
<#
    .Synopsis
        Will run script currently edited in ISE.
    .Description
        Will run script currently edited ISE. If it's not saved - it will create scriptblock on a fly.
        Difference between this command and F5 is that script will not be dot-sourced.
        So if you want to have 'clean' environment between script invokes you probably will need it.
        When added with module it will try to assign F4 for this command.
        It has one switch parameter to use when run from cli: Autosave, that will save file before running it.
        Without it file that was not saved will be converted to scriptblock and invoked as such.
        For edited & saved modules it will re-load them as the only reasonable action (some day...).
    .Example
        Invoke-Script -AutoSave
        Will save your script (if not yet saved) and run it without changing current environment.
    .Example
        Invoke-Script
        Will run a script/ scriptblock using currently opened file. If module is opened it will re-import it.
#>
    
    [CmdletBinding()]
    param (
        # Parameter that will force a file to be autosaved before it will be invoked.
        [Parameter()]
        [switch]$AutoSave
    )

    if ($file = $psISE.CurrentFile) {
        if (Test-Path $file.FullPath) {
            Write-Verbose 'File exists...'
            if (-not $File.IsSaved) {
                if ($AutoSave) {
                    $file.Save()
                } else {
                    Write-Verbose 'Convert contents to scriptblock'
                    & ([scriptblock]::Create($file.Editor.Text))
                    return
                }
            }
        } else {
            if ($AutoSave) {
                Write-Verbose 'Save a file as random .ps1 and run'
                $NewName = ([io.path]::GetRandomFileName()) + '.ps1'
                $file.SaveAs($NewName)
                & $NewName
                return
            } else {
                Write-Verbose 'Convert contents to scriptblock'                
                & ([scriptblock]::Create($file.Editor.Text))
                return
            }
        } 
        switch ((Get-Item $file.FullPath).extension) {
            '.ps1' {
                Write-Verbose 'Normal script, need to run it!'
                & $file.FullPath
            }
            { $_ -match '\.ps(m|d)1' } {
                Write-Verbose 'Module, try to (re)load it!'
                # TODO : Make it work! :P 
                # Import-Module -Force ($file.FullPath) -Global
                Write-Host 'Module... skipped!'
            }
            default {
                throw 'Can not perform any action with currently opened file'
            }
        }
        
    } else {
        throw 'No file opened in current tab!'
    }
}

Add-MyMenuItem Invoke-Script 'Invoke opened script without dot-sourcing it' 'F4'

function Update-SnippetMenu {

<#
    .Synopsis
        Updates/ creates custom snippet menu.
    .Description
        This function will take any snippets that you have in location (either default or selected one) and add those to ISEFun 'Code Snippets' menu.
        It uses .ps1 file to make it easier to modify files in ISE (with syntax highlighting and stuff...)
    .Example
        Update-SnippetMenu
        Checks for files in $PSScriptRoot\ISESnippets folder and add them to 'Code Snippets' menu.
#>
    param (
        [string]$Path = "$PSScriptRoot\ISESnippets"
        )
    foreach ($file in Get-ChildItem $Path -filter *.ps1) {
        $command = @"
        if (!(`$file = `$psISE.CurrentFile)) {
            `$file = `$psISE.CurrentPowerShellTab.Files.Add()
        }
        `$file.Editor.InsertText(
          `$( (Get-Content $($file.FullName))  | Out-String )
          )
"@
        $Name = $file.BaseName -replace '_', ' '
        Add-MyMenuItem $command "Insert $Name" $null 'Code Snippets'
    }
}

Add-MyMenuItem Update-SnippetMenu 'Adds/ updates code snippets menu'

function New-Snippet {

<#
    .Synopsis
        Creates new snippet from current file/ selection.
    .Description
        This function will create new snippets for you. To simplify usage in ISE it has mandatory parameter for snippet name (GUI prompt).
        It will by default store snippets under modules root folder in 'ISESnippets'.
    .Example
        New-Snippet -SnippetName 'My funny name that will have underscore instead of **?? special \ chars'
        Will create new file (with rather odd name) with current selection (or file, if nothing was selected).
        All special chars and spaces will be replace with underscore ( _ ).
#>
    param(
        [Parameter(Mandatory = $true, HelpMessage = 'Please specify name of the snippet')]
        [Alias("SN","Name")]
        [string]$SnippetName,
        [string]$Path = "$PSScriptRoot\ISESnippets"
    )
    if ($file = $psISE.CurrentFile) {
        if (!($Value = $file.Editor.SelectedText)) {
            $Value = $file.Editor.Text
        }   
    } else {
        Write-Error "No files opened in this tab!"
        return
    }
    $Name = ($SnippetName -replace '[\s+\\\*\?]', '_') + '.ps1'
    New-Item -Force -ItemType file -Path (Join-Path $Path $Name) -Value $Value | Out-Null
}

Add-MyMenuItem New-Snippet 'Create new snippet from selection/ file'

function Show-Top {
    PARAM (
        [int]$Count = 20,
        [int]$Sleep = 5,
        [string]$Property = 'WS'
        )
    $TopTab = $psISE.PowerShellTabs.Add()
    sleep 10
    if ($TopTab.CanInvoke) {
        $TopTab.DisplayName = "TOP$Count - $Property"
        $psISE.PowerShellTabs.SetSelectedPowerShellTab($TopTab)
        $TopTab.Invoke([scriptblock]::Create(@"
            Register-WmiEvent -Query "SELECT * From Win32_ProcessStartTrace"
            Register-WmiEvent -Query "SELECT * From Win32_ProcessStopTrace"
            `$formaterS = "{0,10} {1,10} {2,10} {3,10} {4,10} {5,10} {6,10} {7,-30}"
            `$formaterD = "{0,10} {1,10:N0} {2,10:N0} {3,10:N0} {4,10:N0} {5,10:N2} {6,10} {7,-30}"
            while (`$true) { 
                function prompt {
                    `$psISE.PowerShellTabs.Remove(`$psISE.CurrentPowerShellTab)
                }

                Clear-Host
                'TOP for PowerShell ISE - from ISEFun module'
                '=' * 50
                `$Processes = Get-Process
                
                `$Started = @(Get-Event | where { `$_.SourceEventArgs.NewEvent.__Class -match 'Start' } | foreach { `$_.SourceEventArgs.NewEvent.ProcessID })
                `$Stopped = @(Get-Event | where { `$_.SourceEventArgs.NewEvent.__Class -match 'Stop' } | foreach { `$_.SourceEventArgs.NewEvent.ProcessID })
                `$Processes += `$DisplayedProcess | where { `$Stopped -contains `$_.Id }
                `$Processes = `$Processes | sort -Descending $Property
                `$DisplayedProcess = `$Processes | select -First $Count
                `$formaterS -f `$('Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName'.Split())
                `$formaterS -f `$(@('-' * 10) * 8)
                foreach (`$process in `$DisplayedProcess) {
                    `$ProcessString = `$formaterD -f `$process.Handles, `$(`$process.NPM / 1KB), `$(`$process.PM/1KB), `$(`$process.WS / 1KB), `$(`$process.VM / 1MB), `$process.CPU, `$process.Id, `$(`$process.Name -replace '(^.{0,29}).*', '`$1')
                    if (`$Stopped -contains `$process.id) {
                        `$ProcessString + "==> PROCESS TERMINATED"
                    } elseif (`$Started -contains `$process.id) {
                        `$ProcessString + "<== NEW PROCESS ADDED"
                    } else {
                        `$ProcessString
                    }
                }
                                                                                                                       
                Get-Event | Remove-Event
                
                "Diplay $Count processes out of `$(`$Processes.Count)"
                sleep $Sleep
            }
"@))
    }
}

Add-MyMenuItem Show-Top

function Edit-HelpExample {

<#
    .Synopsis
        Simple function to copy help examples (as useable code) and it's description (as comments) to empty file in ISE
    .Description
        If you want to see what examples are available for a given command - that function is for you.
        It can easily get all examples in a way that you can just highlight them and get results back.
        Only basic testing done, so probably something is still missing...
    .Example
        Get-HelpExample Get-ChildItem
        Copies all 7 examples from Get-ChilItem cmdlet to empty file.
    .Example
        Get-HelpExample Get-HelpExample
        If I did everything right you will probably see this command, text that I'm currently typing and anything above/ below in this section of function
        
#> 
 
    param (
    # Name of the command that will be used to get examples
    [Parameter(Mandatory = $true, HelpMessage = 'Name of the command that will be used to get examples')]
    [ValidateScript( { (Get-Help $_).Examples.example })]
    [string]$Name
    )
    if ($psISE) {
        $Editor = $psISE.CurrentPowerShellTab.Files.Add().Editor
        $Editor.InsertText("# Examples from help - $Name`n")
        foreach ($example in (Get-Help $Name).Examples.example) {
                $Editor.InsertText(@"
<# START :=> $(($example.title) -replace '-')

$(($example.remarks | select -ExpandProperty text | where { $_ }) -join "`n")

END :=> $(($example.title) -replace '-') #>

$(($example | select -ExpandProperty code) -replace '(?m:^C:(\\\w*)+>)')

"@)                
        }
    } else {
        throw "You must use this function/ script in PowerShell ISE!"
    }
}

Add-MyMenuItem Edit-HelpExample 'Edit Help Example'

# Next few lines are just garbage you get when you wanna be smart and create GUI in the script.
# Forgive me for adding this stuff here, I could probably compile it in some dll and skip this but...
# ... well - it gives impression that my module is bigger than it actually is. ;)
#
# Our form to change colours... :)
$handler_bClose_Click= 
{
    $Main.Hide()
}

$handler_bColor_Click= 
{
    $Dialog = New-Object Windows.Forms.ColorDialog -Property @{
        Color = [drawing.color]::FromArgb($psISE.Options.TokenColors.Item($Combo.SelectedItem).ToString())
        FullOpen = $true
    }
    
    if ($Dialog.ShowDialog() -eq 'OK') {
        $psISE.Options.TokenColors.Item($Combo.SelectedItem) = [windows.media.color]::FromRgb($Dialog.Color.R, $Dialog.Color.G, $Dialog.Color.B)
        $Combo.ForeColor = $Dialog.Color

    }

}

$handler_selectedValue = {
    $Combo.ForeColor = [drawing.color]::FromArgb($psISE.Options.TokenColors.Item($Combo.SelectedItem).ToString())
    $bColor.Focus()
}

$OnLoadForm_StateCorrection = {
	$Main.WindowState = $InitialFormWindowState
    $Combo.SelectedIndex = 0
}

$Script:Main = New-Object Windows.Forms.Form -Property @{
    Text = "Token colors selector"
    MaximizeBox = $False
    Name = "Main"
    HelpButton = $True
    MinimizeBox = $False
    ClientSize = New-Object System.Drawing.Size 426, 36
}
$Main.DataBindings.DefaultDataSourceUpdateMode = 0

$Combo = New-Object Windows.Forms.ComboBox -Property @{
    FormattingEnabled = $True
    Size = New-Object System.Drawing.Size 239, 23
    Name = "Combo"
    Location = New-Object System.Drawing.Point 12, 7
    Font = New-Object System.Drawing.Font("Lucida Console",11.25,0,3,238)
    TabIndex = 4
    DropDownStyle = 'DropDownList'
    }
$Combo.DataBindings.DefaultDataSourceUpdateMode = 0
$Combo.Items.AddRange($psISE.Options.TokenColors.Keys)
$Combo.Add_SelectedValueChanged($handler_SelectedValue)

$InitialFormWindowState = New-Object Windows.Forms.FormWindowState

$bClose = New-Object Windows.Forms.Button -Property @{
    TabIndex = 2 
    Name = "bClose"
    Size = New-Object System.Drawing.Size 75, 23
    UseVisualStyleBackColor = $True
    Text = "Close"
    Location = New-Object System.Drawing.Point 338, 7
    }
$bClose.DataBindings.DefaultDataSourceUpdateMode = 0
$bClose.add_Click($handler_bClose_Click)

$bColor = New-Object Windows.Forms.Button -Property @{
    TabIndex = 1
    Name = "bColor"
    Size = New-Object System.Drawing.Size 75, 23
    UseVisualStyleBackColor = $True
    Text = "Color"
    Location = New-Object System.Drawing.Point 257, 7
}
$bColor.DataBindings.DefaultDataSourceUpdateMode = 0
$bColor.add_Click($handler_bColor_Click)

$Main.Controls.AddRange(@($bColor,$bClose,$Combo))
$InitialFormWindowState = $Main.WindowState
$Main.add_Load($OnLoadForm_StateCorrection)
$HelpMessage = @'
This GUI will help you change you token colors.
It's updating text color as you select tokens that you want to modify.
Button 'Color' opens up color dialog.
I won't describe actions performed by 'Close' button. I hope you are able to guess it... ;)
'@
$Main.add_HelpButtonClicked( { [void][windows.forms.MessageBox]::Show($HelpMessage,'Help','OK','Information')})

function Set-TokenColor {

<#
    .Synopsis
        GUI to add some Token Colors.
    .Description
        Really. It is just that. No more to it. Seriously!
        OK. GUI is pretty smart. You can select tokens that are available, color will change and match the one you currently have. See for yourself. ;)
    .Example
        Can show you click-click-click example :)
#>
    $Script:Main.ShowDialog()| Out-Null
}

Add-MyMenuItem Set-TokenColor 'Set Token Colors' $null 'Token colors'

function Expand-Alias {

<#
    .Synopsis
        Function to expand all command aliases in current script.
    .Description
        If you want to expand all aliases in a script/ module that you write in PowerShell ISE - this function will help you with that.
        It's using Tokenizer to find all commands, Get-Alias to find aliases and their definition, and simply replace alias with command hidden by it.
    .Example
        Expand-Alias
#>

    # Read in current file
    if (!$psISE.CurrentFile) {
        throw 'No files opened!'
    }
    
    if ( -not ($Script = $psISE.CurrentFile.Editor.Text) ) {
        throw 'No code!'
    }
    
    $line = $psISE.CurrentFile.Editor.CaretLine
    $column = $psISE.CurrentFile.Editor.CaretColumn
    
    if ( -not ($commands = [System.Management.Automation.PsParser]::Tokenize($Script, [ref]$null) | Where-Object { $_.Type -eq 'Command' } | Sort-Object -Property Start -Descending) ) {
        return
    } 
    foreach ($command in $commands) {
        if (Get-Alias $command.Content -ErrorAction SilentlyContinue) {
            # $command
            $psISE.CurrentFile.Editor.Select($command.StartLine, $command.StartColumn, $command.EndLine, $command.EndColumn)
            $psISE.CurrentFile.Editor.InsertText($(Get-Alias $command.Content | Select-Object -ExpandProperty Definition))
        }
    }
    $psISE.CurrentFile.Editor.SetCaretPosition($line, $column)
}

Add-MyMenuItem Expand-Alias

function Edit-Function {

<#
    .Synopsis
        Simpe function to edit functions in ISE.
    .Description
        Need to edit function on-the-fly? Want to see how a given function looks like to change it a bit and rename it?
        Or maybe just preparing module and you want to change functions you define to make sure changes will work as expected?
        Well, with Edit-Function, which is very simple (thank you PowerShell team!) you can do it. :)
    .Example
        Edit-Function Edit-Function
        
        Description
        -----------
        You can open any function that exists in your current session, including the function that you reading help to now.
        Be careful with that one though. If you change it in wrong direction you may not be able to open it again and fix it.
        At least not in the way you could originaly, with Edit-Function. :)
#>

    [CmdletBinding()]
    param (
    [Parameter(Mandatory=$true,HelpMessage='Function name is mandatory parameter.')]
    [ValidateScript({Get-Command -CommandType function $_})]
    [string]
    $Name
    )
  
    $file = $psISE.CurrentPowerShellTab.Files.Add()
    $file.Editor.InsertText("function $name {`n")
    $file.Editor.InsertText($(Get-Command -CommandType function $name | Select-Object -ExpandProperty definition))
    $file.Editor.InsertText("}")
}

Add-MyMenuItem Edit-Function

function Copy-HistoryItem {

<#
    .Synopsis
        Function build using WPK to give you functionality similar to one you already have in PowerShell.exe
    .Description
        Display you command history and let you choose from it. Copies selected command to you commandPane.
    .Example
        Copy-HistoryItem
        GUI, so it's not easy to show examples...
#>

    try {
        New-Window -Width 800 -Height 100 {
            New-ListBox -On_PreviewMouseDoubleClick {
                $psISE.CurrentPowerShellTab.CommandPane.InsertText($this.SelectedValue)
                $this.parent.close()
            } -Items $(Get-History | Select-Object -ExpandProperty CommandLine)
        } -Show
    } catch {
        throw 'Requires WPK to work, will be rewritten soon...'
    }
}

Add-MyMenuItem Copy-HistoryItem 'Copy item from History' F7

function Invoke-CurrentLine {

<#
    .Synopsis
        Invokes line where the caret is currently present.
    .Description
        Similar to the one in ISEPack (I've discovered that it was in ISEPack soon after I've written it).
        Mine is probably not as good as the one from ISEPack (I would be surprised if that would be the opposite ;) )
        All you need to do is stop in line you want to check and hit Shitf + F8
    .Example
        Invoke-CurrentLine
        Invokes current line where       
#>

    $Editor = $psISE.CurrentFile.Editor
    $row = $Editor.CaretLine
    $col = $Editor.CaretColumn
    $Editor.Select($row, 1, $row, $Editor.GetLineLength($row)+1)
    [scriptblock]::Create($Editor.SelectedText).Invoke()
    $Editor.SetCaretPosition($row,$col)
}

Add-MyMenuItem Invoke-CurrentLine 'Invoke Current Line' 'Shift + F8'

New-Alias -Name edfun -Value Edit-Function
New-Alias -Name expa -Value Expand-Alias
New-Alias -Name cphi -Value Copy-HistoryItem

Export-ModuleMember -Function * -Alias *

# Get rid off menu if module is going to be unloaded.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    [void]$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Remove($MyISEMenu)
}